#pragma once

#include<iostream>
#include<semaphore.h>
#include<pthread.h>
#include<vector>
using namespace std;


const int gCap = 10;

template<class T>
class RingQueue
{
public:
    RingQueue(int cap = gCap)
        :ringqueue_(cap)
        ,pIndex(0)
        ,cIndex(0)
    {
        //生产
        sem_init(&roomSem_, 0, ringqueue_.size());
        //消费
        sem_init(&dataSem_, 0, 0);
        pthread_mutex_init(&pmutex_, nullptr);
        pthread_mutex_init(&cmutex_, nullptr);
    }

    ~RingQueue()
    {
        sem_destroy(&roomSem_);
        sem_destroy(&dataSem_);
        pthread_mutex_destroy(&pmutex_);
        pthread_mutex_destroy(&cmutex_);
    }

    //生产
    void push(const T& in)
    {
        sem_wait(&roomSem_);//无法被多次的申请

        pthread_mutex_lock(&pmutex_);

        ringqueue_[pIndex_] = in;//生产的过程
        pIndex_++;
        pIndex_ %= ringqueue_.size();//更新下标,保证环形特征

        pthread_mutex_unlock(&pmutex_);

        sem_post(&dataSem_);
    }

    //消费
    T pop()
    {
        sem_wait(&dataSem_);

        pthread_mutex_lock(&cmutex_);

        T temp = ringqueue_[cIndex_];
        cIndex_++;
        cIndex_ %= ringqueue_.size();//更新下标,保证环形特征

        pthread_mutex_unlock(&cmutex_);
        
        sem_post(&roomSem_);

        return temp;
    }

private:
    vector<T> ringqueue_;//环形队列
    sem_t roomSem_;//衡量空间计数器, productor
    sem_t dataSem_;//衡量数据计数器, consumer
    uint32_t pIndex_;//当前生产者写入的位置,如果是多线程,pIndex_也是临时资源
    uint32_t cIndex_;//当前消费者读取的位置,如果是多线程,cIndex_也是临时资源
    pthread_mutex_t pmutex_;
    pthread_mutex_t cmutex_;
};